import React, { Component, PropTypes } from 'react';
import ReactDOM from 'react-dom';
import * as validate from '../../utils/validation';
import { deepEqual } from '../../utils/objects';
import RangeNumber from './RangeNumber';
import { Row, Col, Form, InputNumber, Input, Radio, Select, DatePicker, TimePicker, TreeSelect, Tree, Cascader, Checkbox, Button, Divider } from 'antd';
import { connect } from 'dva';
import moment from 'moment';
import SearchInput from './SearchInput'
import SearchInput2 from './SearchInput2'
const FormItem = Form.Item;
const RadioGroup = Radio.Group;
const ButtonGroup = Button.Group;
const { TextArea } = Input;
const TreeNode = Tree.TreeNode
class DataEdit extends React.Component {
    constructor(props) {
        super(props);
        let positons = {}
        let sum = 0.0, row = 0;
        props.controls.map((c, i) => {
            const g2 = c.grid / 24
            sum = sum + c.grid > 1 ? g2 : c.grid
            if (sum > 1) {
                row++;
                sum = 0;
            }
            if (!positons[row]) {
                positons[row] = []
            }
            positons[row].push(i);
            if (sum === 1) {
                row++;
                sum = 0;
            }
        })
        this.state = {
            positons,
            record: props.record
        };
    }
    componentWillReceiveProps(nextProps) {
        if (!deepEqual(nextProps.record, this.props.record)) {
            this.setState({ record: nextProps.record });
        }
    }
    componentDidMount() {
        const selectFirst = this.props.selectFirst
        if (!selectFirst) {
            return
        }
        const form = ReactDOM.findDOMNode(this.refs.editForm);
        let div = form.querySelector('div.ant-form-item-control');
        if (!div) {
            return
        }
        const tagName = div.firstChild.tagName
        if (tagName === "INPUT") {
            div.firstChild.focus()
        } else {
            div.firstChild.click()
        }
    }
    onEditChange(e) {
        this.state.isChange = true;
    }
    closeMsg() {
        this.setState({ showMsg: false });
    }
    validateField(cont, rule, value, callback) {
        let valType = "string"
        let newVal = value
        if (cont.multiple) {
            valType = "array"
            if (!cont.sep) {
                cont.sep = ","
            }
            newVal = value.join(cont.sep)
        } else if (cont.dataType === "number") {
            valType = "number"
        }
        if (cont.validator) {
            cont.formData = this.props.form.getFieldsValue();
        }
        const ret = validate.validate(value, valType, cont)
        if (ret === true) {
            callback()
        } else {
            callback(ret)
        }
    }
    getFieldDecoratorOption(cont) {
        const { name, required, type, min, max, label, dataType, fetch, multiple, onChange, onBlur, disabled, labelInValue } = cont;
        const record = this.state.record;
        let initVal = record[name];
        if (fetch) {
            if (type === 'cascader-select') {
                const ops3 = this.props.optionDatas[fetch.daoName + "_cascader"];
                if (ops3) {
                    initVal = ops3[initVal];
                } else {
                    initVal = [];
                }
            } else if (type === 'select' && labelInValue) {
                if (initVal === null || initVal === undefined) {
                    initVal === undefined
                } else {
                    const ops = this.props.optionDatas[fetch.daoName];
                    for (let i = 0; i < ops.length; i++) {
                        if (ops[i].key === initVal) {
                            initVal = ops[i];
                            break
                        }
                    }
                }
            } else {
                initVal = initVal === null || initVal === undefined ? '' : '' + initVal
            }
        } else if (dataType === 'date' || dataType === 'datetime') {
            if (initVal && initVal.length === 8) {
                initVal = initVal.substr(0, 4) + "/" + initVal.substr(4, 2) + "/" + initVal.substr(6, 2)
            }
            const dateFormat = 'YYYY/MM/DD';
            const obj = new Date(initVal);
            if (isNaN(obj.getTime())) {
                initVal = null
            } else {
                initVal = initVal ? moment(initVal, dateFormat) : null;
            }
        } else if (dataType === 'month') {
            if (initVal && initVal.length === 6) {
                initVal = initVal.substr(0, 4) + "-" + initVal.substr(4, 2)
            }
            const dateFormat = 'YYYYMM';
            const obj = new Date(initVal);
            if (isNaN(obj.getTime())) {
                initVal = null
            } else {
                initVal = initVal ? moment(initVal, dateFormat) : null;
            }

        }
        if (multiple || type === 'checkbox-group') {
            if (initVal === null || initVal === undefined || initVal === "") {
                initVal = []
            } else if (typeof (initVal) === "string") {
                initVal = initVal.split(",");
            }
        }
        let option = { initialValue: initVal }
        option.rules = []
        if (required) {
            let rule = { required: true, message: `请输入${label}!` }
            if (multiple) rule.type = "array";
            option.rules.push({ required: true, message: `请输入${label}!` })
        }
        option.rules.push({ validator: this.validateField.bind(this, cont) })
        if (onChange) {
            option.onChange = onChange
        }
        if (disabled) {
            option.disabled = true;
        }
        return option
    }
    getAntDControl(contProps) {
        const contType = contProps.type;
        const { multiple, placeholder, fetch, name, data, label, labelInValue, onClick, isDisabled, defaultValue, disabledDate, onBlur, onSearch } = contProps
        const getDataOptions = (() => {
            let dataOptions;
            if (fetch) {
                dataOptions = this.props.optionDatas[fetch.daoName];
            } else {
                if (!data || !(data instanceof Array) || data.length == 0) {
                    dataOptions = [];
                } else if (typeof data[0] === "object") {
                    const d0 = data[0]
                    if (!d0.value || !d0.label) {
                        throw new Error(`${contProps.label}指定的data必须包含value和label属性！`)
                    }
                    dataOptions = data
                } else {
                    dataOptions = []
                    data.map(d => dataOptions.push({ value: d, label: d }))
                }
            }
            return dataOptions ? dataOptions : [];
        }).bind(this)
        let { optionTpl, valueTpl } = contProps
        if (!optionTpl) {
            optionTpl = "label"
        }
        if (!valueTpl) {
            valueTpl = "value"
        }
        let cont;
        switch (contType) {
            case 'month':
                cont = <DatePicker.MonthPicker disabled={isDisabled} disabledDate={disabledDate} />
                break;
            case 'date':
                cont = <DatePicker disabled={isDisabled} />
                break;
            case 'time':
                cont = <TimePicker />
                break;
            case 'datetime':
                cont = <DatePicker showTime format="YYYY-MM-DD HH:mm:ss" />
                break;
            case 'range-month':
                cont = <DatePicker.RangePicker format="YYYY-MM" />
                break;
            case 'range-date':
                cont = <DatePicker.RangePicker format="YYYY-MM-DD" />
                break;
            case 'range-datetime':
                cont = <DatePicker.RangePicker showTime format="YYYY-MM-DD HH:mm:ss" />
                break;
            case 'range-number':
                cont = <RangeNumber />
                break;
            case 'select':
                const Option = Select.Option;
                let options = getDataOptions()
                let children = []
                options.map(o => {
                    let value = o[valueTpl]
                    children.push(<Option key={o.value} value={value} >{o[optionTpl]}</Option>)
                })
                cont = <Select key={name + '_select'} multiple={multiple} placeholder={placeholder} labelInValue={labelInValue} size='default' disabled={isDisabled}>{children}</Select>
                break;
            case 'tree-select':
                const treeData = getDataOptions()
                const loop = data => data.map((item) => {
                    if (item.children) {
                        return (
                            <TreeNode key={item.key} value={item[valueTpl]} title={item[optionTpl]}>
                                {loop(item.children)}
                            </TreeNode>
                        );
                    }
                    return <TreeNode key={item.key} value={item[valueTpl]} title={item[optionTpl]} />;
                });
                cont = <TreeSelect showSearch treeNodeFilterProp='label' multiple={multiple} treeCheckable={multiple} placeholder={placeholder} disabled={isDisabled}>
                    {loop(treeData)}
                </TreeSelect>
                break;
            case 'cascader-select':
                cont = <Cascader showSearch options={getDataOptions()} placeholder={placeholder} />
                break;
            case 'checkbox':
                cont = <Checkbox disabled={isDisabled} defaultChecked={false}>{contProps.label}</Checkbox>
                break;
            case 'checkbox-group':
                const CheckboxGroup = Checkbox.Group;
                cont = <CheckboxGroup options={getDataOptions()} />
                break;
            case 'radio-group':
                let data = getDataOptions();
                cont = <RadioGroup>{data.map(d => <Radio value={d[valueTpl]} key={d.value}>{d[optionTpl]}</Radio>)}</RadioGroup>
                break;
            case 'search':
                cont = <SearchInput {...contProps.fetch} placeholder={placeholder} />
                break;
            case 'search2':
                cont = <SearchInput2 initValue={contProps.defaultLabel} params={contProps.props} placeholder={placeholder} />
                break;
            case 'disabled':
                cont = <Input disabled placeholder={placeholder}/>
                break;
            case 'button-group':
                const bData = contProps.data
                cont = <ButtonGroup size='default' >{bData.map(d => <Button value={d[valueTpl]} key={d.value} onClick={d.onClick} loading={d.loading}>{d[optionTpl]}</Button>)}</ButtonGroup>
                break;
            case 'input-number-min1':
                cont = <InputNumber size='default' min={1} max={100} step={0.1000} />
                break;
            case 'input-number-min0':
                cont = <InputNumber size='default' min={0} max={100} step={0.1000} />
                break;
            case 'input-large':
                cont = <Input size='large' />
                break;
            case 'textarea':
                cont = <TextArea rows={2} placeholder={placeholder} />
                break;
            case 'textarea2':
                cont = <TextArea rows={10} placeholder={placeholder} />
                break;
            case 'Search3':
                const Search = Input.Search;
                cont = <Search onSearch={onSearch} />
                break;
            case 'br':
                cont = <br />
                break;
            default:
                cont = <Input size='default' disabled={isDisabled} placeholder={placeholder} onBlur={onBlur} />
        }
        return cont
    }
    getControls() {
        const { getFieldDecorator } = this.props.form;
        const { controls, labelColSpan, wrapperColSpan } = this.props;
        const record = this.state.record;
        const formItemLayout = {
            labelCol: { span: 6 },
            wrapperCol: { span: 16 },
        };
        let formItems = [];
        let grid = 0;
        const count = controls.length
        controls.map(c => {
            let layout = formItemLayout;
            if (c.layout && c.layout.wrapperSpan > 0) {
                layout = {
                    labelCol: { span: c.layout.labelSpan },
                    wrapperCol: { span: c.layout.wrapperSpan }
                };
            }
            if (count === 1 || this.props.clearItemMargin) {
                layout.style = { margin: 0 }
            }
            let label = c.label;
            if (c.type === "button-group" || c.type === "checkbox") {
                label = '';
                layout = {
                    labelCol: { span: 0 },
                    wrapperCol: { span: 23 },
                };
            }
            formItems.push(
                <FormItem  {...layout} label={label} key={c.name} style={{ marginBottom: 0 }}>
                    {getFieldDecorator(c.name, this.getFieldDecoratorOption(c))(this.getAntDControl(c))}
                </FormItem>
            )
        })
        return formItems;
    }
    render() {
        const conts = this.getControls();
        let rows = []
        const p = this.state.positons;
        const cs = this.props.controls;
        Object.keys(p).map((k, j) => {
            let cols = []
            p[k].map(i => {
                let grid = cs[i].grid
                if (grid <= 1) {
                    grid = Math.round(grid * 24)
                }
                cols.push(<Col key={i} span={grid}>{conts[i]}</Col>)
            })
            rows.push(<Row key={j}>{cols}</Row>)
        })
        return (
            <span>
                <Form layout="horizontal" ref="editForm">
                    {rows}
                </Form>
            </span>
        );
    }
}
DataEdit.propTypes = {
    controls: PropTypes.array,
    record: PropTypes.object,
    selectFirst: PropTypes.bool,
    clearItemMargin: PropTypes.bool,
    isDisabled: PropTypes.bool,
    defaultValue: PropTypes.string,
    disabledDate: PropTypes.string,
};
DataEdit.defaultProps = {
    controls: [],
    record: {},
    selectFirst: false,
    clearItemMargin: false,
    isDisabled: false,
    defaultValue: "",
    disabledDate: ""
};
export default function dataEditCreate(daoName) {
    function mapStateToProps(state) {
        const { optionDatas } = state[daoName];
        return {
            loading: state.loading.models[daoName],
            optionDatas
        }
    }
    return Form.create()(connect(mapStateToProps)(DataEdit));
}

